package com.handinfo.engine;

import java.io.DataInputStream;
import java.io.IOException;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import com.handinfo.engine.resource.ObjectAdapter;
import com.handinfo.engine.resource.ResHead;
import com.handinfo.engine.resource.Resource;
import com.handinfo.engine.resource.Serializeable;
import com.handinfo.engine.resource.SerializeableImage;
import com.handinfo.util.Tools;
/**
 * 背景类 背景是场景的组成部分，我们将背景分为三种类型，包括静态图片的背景，通常见于俄罗斯方
 * 块、连连看这种类型的单屏休闲游戏中。卷轴背景整图，横版过关或者纵版过关的动作游戏中
 * 非常常见。砖块拼接背景，像我们生活中装修的地砖一样，用小图块来拼接成完整的地图背景 这种背景类型在角色扮演、动作、射击游戏等等各种游戏类型中都会运用
 * F1:背景对象将支持无限层背景，并且可以由上面介绍的三种类型任意混合 F2:背景对象提供足够丰富的API来实现背景的灵活绘制，可以以任意顺序来绘制各层背景
 * F3:背景对象会自动识别是否使用缓存来进行绘制提速，也可手动来强制使用缓存
 * 
 * @author Xia Mingwei
 * @version 1.0
 */
public class Background extends Serializeable
{
	public byte m_type; // 背景类型，目前为保留，无作用
	public int m_color; // 背景底色
	public int m_tileW; // 背景格宽度
	public int m_tileH; // 背景格高度
	public int m_columns; // 背景横向格数
	public int m_rows; // 背景纵向格数
	public int m_layerCount; // 背景层数
	public int m_cameraW; // 摄像机宽度
	public int m_cameraH; // 摄像机高度
	public int m_cameraX; // 摄像机X坐标
	public int m_cameraY; // 摄像机Y坐标
	public int m_frameCount = 0; // 背景运行帧数，主要用来一些背景动态效果的处理
	public Layer[] m_layers; // 背景层集合
	public Layer m_phylayer; // 物理层

	/**
	 * 缓存相关
	 */
	public boolean m_updateBg = true;
	public boolean m_isUseBuffer = false; // 是否使用缓存
	private static Image s_bufImage;
	private static Graphics s_bufG;
	private int m_bufImageWidth;
	private int m_bufImageHeight;
	private int m_prevX0;
	private int m_prevY0;
	private int m_prevX1;
	private int m_prevY1;

	public Background()
	{

	}


	public void blackBuffer()
	{
		s_bufG.setClip(0, 0, AbstractGameScreen.SCREEN_WIDTH,
				AbstractGameScreen.SCREEN_HEIGHT);
		s_bufG.setColor(0x0);
		s_bufG.fillRect(0, 0, AbstractGameScreen.SCREEN_WIDTH,
				AbstractGameScreen.SCREEN_HEIGHT);
	}

	/**
	 * 为每个背景层载入用到的资源
	 * 
	 * @see #releaseResource
	 * @see #dispose
	 */
	public void initResource()
	{
		// 缓存相关处理
		if (m_isUseBuffer) {
			m_updateBg = true;
			m_bufImageWidth = ((m_cameraW + (m_tileW << 1) - 1) / m_tileW)
					* m_tileW;
			m_bufImageHeight = ((m_cameraH + (m_tileH << 1) - 1) / m_tileH)
					* m_tileH;
			if (s_bufImage == null) {
				s_bufImage = Image.createImage(m_bufImageWidth,
						m_bufImageHeight);
				if (Tools.DEBUG) {
					System.err.println("建立卡马克缓存");
				}
				if (s_bufG == null) {
					s_bufG = s_bufImage.getGraphics();
				}
				blackBuffer();
			}
		}
		for (int i = 0; i < m_layerCount; i++) {
			m_layers[i].initResource();
		}
	}

	/**
	 * 背景呼吸方法，用于每帧执行
	 */
	public void tick()
	{
		for (int i = 0; i < m_layerCount; i++) {
			m_layers[i].tick();
		}
		m_frameCount++;
	}

	/**
	 * 设置摄像机坐标
	 * 
	 * @param cameraX
	 * 摄像机X坐标
	 * @param cameraY
	 * 摄像机Y坐标
	 */
	public void setCameraXY(int cameraX, int cameraY)
	{
		// 如果新摄像机位置超过上次摄像机所在位置一个格子，则背景缓存需要更新
		if (Math.abs(cameraX - this.m_cameraX) > m_tileW)
			m_updateBg = true;
		if (Math.abs(cameraY - this.m_cameraY) > m_tileH)
			m_updateBg = true;
		this.m_cameraX = cameraX;
		this.m_cameraY = cameraY;
	}

	/**
	 * 设置摄像机宽高
	 * 
	 * @param w
	 * @param h
	 */
	public void setCameraWH(int w, int h)
	{
		m_cameraW = w;
		m_cameraH = h;
	}

	/**
	 * 绘制某个特定的背景层
	 * 
	 * @param g
	 * @param layerIndex
	 * 背景层索引
	 */
	public void draw(Graphics g, int layerIndex)
	{
		if (layerIndex < 0 || layerIndex >= m_layerCount)
			return;
		m_layers[layerIndex].drawLayer(g, m_cameraX, m_cameraY);
	}

	/**
	 * 绘制指定范围内的背景层
	 * 
	 * @param g
	 * @param startLayerIndex
	 * 开始背景层索引
	 * @param endLayerIndex
	 * 结束背景层索引
	 */
	public void draw(Graphics g, int startLayerIndex, int endLayerIndex)
	{
		if (endLayerIndex < startLayerIndex) {
			int tempIndex = startLayerIndex;
			startLayerIndex = endLayerIndex;
			endLayerIndex = tempIndex;
		}
		// 给定的索引超过背景层数量
		if (startLayerIndex >= m_layerCount)
			return;
		// 结束背景层索引超过背景层数量
		if (endLayerIndex >= m_layerCount)
			endLayerIndex = m_layerCount - 1;
		for (int i = startLayerIndex; i <= endLayerIndex; i++) {
			m_layers[i].drawLayer(g, m_cameraX, m_cameraY);
		}
	}

	/**
	 * 绘制指定范围内的缓存背景层，仅拼接图层支持缓存
	 * 
	 * @param g
	 * @param startLayerIndex
	 * 开始背景层索引
	 * @param endLayerIndex
	 * 结束背景层索引
	 */
	public void drawBuffer(Graphics g, int startLayerIndex, int endLayerIndex)
	{
		if (endLayerIndex < startLayerIndex) {
			int tempIndex = startLayerIndex;
			startLayerIndex = endLayerIndex;
			endLayerIndex = tempIndex;
		}
		// 给定的索引超过背景层数量或未使用缓存
		if (startLayerIndex >= m_layerCount || !m_isUseBuffer)
			return;
		// 结束背景层索引超过背景层数量
		if (endLayerIndex >= m_layerCount)
			endLayerIndex = m_layerCount - 1;
		drawBgFast(g, startLayerIndex, endLayerIndex, m_cameraX, m_cameraY);
	}

	/**
	 * 卡马克卷轴绘制法来绘制缓存背景
	 * 
	 * @param g
	 * @param startIndex
	 * @param endIndex
	 * @param camX
	 * @param camY
	 */
	private void drawBgFast(Graphics g, int startIndex, int endIndex, int camX,
			int camY)
	{
		int currX0 = camX / m_tileW;
		int currY0 = camY / m_tileH;
		int currX1 = (camX + m_cameraW) / m_tileW;
		int currY1 = (camY + m_cameraH) / m_tileH;
		int start, end;

		if (m_updateBg) {
			m_updateBg = false;
			drawBgPart(startIndex, endIndex, currX0, currY0, currX1, currY1);
			m_prevX0 = currX0;
			m_prevY0 = currY0;
			m_prevX1 = currX1;
			m_prevY1 = currY1;
		}
		else {
			if (m_prevX0 != currX0 || m_prevX1 != currX1) {
				if (m_prevX0 < currX0 || m_prevX1 < currX1) {
					start = m_prevX1 + 1;
					end = currX1;
				}
				else {
					start = currX0;
					end = m_prevX0 - 1;
				}
				drawBgPart(startIndex, endIndex, start, currY0, end, currY1);
				m_prevX0 = currX0;
				m_prevX1 = currX1;
			}
			if (m_prevY0 != currY0 || m_prevY1 != currY1) {
				if (m_prevY0 < currY0 || m_prevY1 < currY1) {
					start = m_prevY1 + 1;
					end = currY1;
				}
				else {
					start = currY0;
					end = m_prevY0 - 1;
				}
				drawBgPart(startIndex, endIndex, currX0, start, currX1, end);
				m_prevY0 = currY0;
				m_prevY1 = currY1;
			}
		}

		int modX0 = camX % m_bufImageWidth;
		int modY0 = camY % m_bufImageHeight;
		int modX1 = (camX + m_cameraW) % m_bufImageWidth;
		int modY1 = (camY + m_cameraH) % m_bufImageHeight;

		g.setClip(0, 0, m_cameraW, m_cameraH);
		g.clipRect(0, 0, m_cameraW, m_cameraH);
		if (modX1 > modX0) {
			if (modY1 > modY0) {
				copyFromBgImage(g, modX0, modY0, m_cameraW, m_cameraH, 0, 0);
			}
			else {
				copyFromBgImage(g, modX0, modY0, m_cameraW, m_cameraH - modY1,
						0, 0);
				copyFromBgImage(g, modX0, 0, m_cameraW, modY1, 0, m_cameraH
						- modY1);
			}
		}
		else {
			if (modY1 > modY0) {
				copyFromBgImage(g, modX0, modY0, m_cameraW - modX1, m_cameraH,
						0, 0);
				copyFromBgImage(g, 0, modY0, modX1, m_cameraH, m_cameraW
						- modX1, 0);
			}
			else {
				copyFromBgImage(g, modX0, modY0, m_cameraW - modX1, m_cameraH
						- modY1, 0, 0);
				copyFromBgImage(g, modX0, 0, m_cameraW - modX1, modY1, 0,
						m_cameraH - modY1);
				copyFromBgImage(g, 0, modY0, modX1, m_cameraH - modY1,
						m_cameraW - modX1, 0);
				copyFromBgImage(g, 0, 0, modX1, modY1, m_cameraW - modX1,
						m_cameraH - modY1);
			}
		}
	}

	private void copyFromBgImage(Graphics g, int srcX, int srcY, int width,
			int height, int destX, int destY)
	{
		s_bufG.setClip(destX, destY, width, height);
		s_bufG.clipRect(destX, destY, width, height);
		g.drawImage(s_bufImage, destX - srcX, destY - srcY, 0);
	}

	private void drawBgPart(int startIndex, int endIndex, int tileX0,
			int tileY0, int tileX1, int tileY1)
	{
		int srcX, srcY;
		int destX, destY;
		int flag;
		short data1;

		int originDestX = (tileX0 * m_tileW) % m_bufImageWidth;
		for (int k = startIndex; k <= endIndex; k++) {
			// 不是拼接背景层则跳过
			if (m_layers[k].m_type != Layer.TYPE_TILEDLAYER
			/* 临时画物理层 && m_layers[k].m_type != Layer.TYPE_PHYSICALLAYER */)
				continue;
			for (int j = tileY0; j <= tileY1; j++) {
				if (j >= m_rows) {
					continue;
				}
				destX = originDestX;
				destY = (j * m_tileH) % m_bufImageHeight;
				if (destY >= m_bufImageHeight) {
					destY -= m_bufImageHeight;
				}
				for (int i = tileX0; i <= tileX1; i++) {
					if (i >= m_columns) {
						continue;
					}
					data1 = m_layers[k].m_data[j * m_columns + i];
					// //test 临时绘制物理层
					// if(m_layers[k].m_data != null) {
					// data1 = m_layers[k].m_data[j * m_columns + i];
					// }
					// else {
					// data1 = m_layers[k].m_phydata[j * m_columns + i];
					// }
					if (data1 == -1) {
						// 最底一层如果没有铺满则会出现bug，临时解决方案
						if (k == 0) {
							s_bufG.setClip(destX, destY, m_tileW, m_tileH);
							s_bufG.clipRect(destX, destY, m_tileW, m_tileH);
							s_bufG.setColor(m_color);
							s_bufG.fillRect(destX, destY, m_tileW, m_tileH);
						}
					}
					else {
						flag = AbstractGameScreen.trans((data1 & 0x4000) != 0,
								(data1 & 0x2000) != 0);
						data1 &= 0x0FFF;
						// tile图片中每行包含的tile个数
						int tileCountPerLine = m_layers[k].m_image.getWidth()
								/ m_tileW;
						srcX = (data1 % tileCountPerLine) * m_tileW;
						srcY = (data1 / tileCountPerLine) * m_tileH;
						s_bufG.setClip(destX, destY, m_tileW, m_tileH);
						s_bufG.clipRect(destX, destY, m_tileW, m_tileH);
//						// 最底一层如果没有铺满则会出现bug，临时解决方案
						if (flag == 0) {
							s_bufG.drawImage(m_layers[k].m_image, destX - srcX,
									destY - srcY, Graphics.LEFT | Graphics.TOP);
						}
						else {
							if (srcX + m_tileW <= m_layers[k].m_image.getWidth() && srcY + m_tileH <= m_layers[k].m_image.getHeight()) {
								s_bufG.drawRegion(m_layers[k].m_image, srcX, srcY,
										m_tileW, m_tileH, flag, destX, destY, 0);
							}
						}
					}
					destX += m_tileW;
					if (destX >= m_bufImageWidth) {
						destX -= m_bufImageWidth;
					}
				}
			}
		}
	}

	/**
	 * 返回物理层数据
	 * 
	 * @return byte[]
	 */
	public byte[] getPhyData()
	{
		for (int i = 0; i < m_layerCount; i++) {
			if (m_layers[i].m_type == Layer.TYPE_PHYSICALLAYER) {
				return m_layers[i].m_phydata;
			}
		}
		return null;
	}

	public byte getCertainTilePhy(int tileX, int tileY)
	{
		return m_phylayer.m_phydata[tileY * m_columns + tileX];
	}

	// //////////////////////////////////////////////////////////////////////////
	// // 各游戏不同的扩展
	// 阻挡块
	public static final int PHY_BLOCK = 0;
	// 特殊物理层
	public static final int PHY_STEP = 5; // 台阶（用于层与层之间的过渡）
	public static final int PHY_SPC0 = 6; // 掩体所在
	public static final int PHY_SPC1 = 7; // 掩体东面
	public static final int PHY_SPC2 = 8; // 掩体南面
	public static final int PHY_SPC3 = 9; // 掩体西面
	public static final int PHY_SPC4 = 10; // 掩体北面
	public static final int PHY_SPC5 = 11; // 子弹可以通过。。人不能通过
	public static final int PHY_SPC6 = 12; // 人可以通过。。子弹不能通过
	public static final int PHY_SPC7 = 13; // 人和子弹都不能通过
	public static final int PHY_SPC8 = 14; // 光线可以通过。。其他没法通过（主要用于墙上摄像机）
	public static final int PHY_FOR_FINDPATH = 15; // AI寻路避免块

	// // 各游戏不同的扩展
	// //////////////////////////////////////////////////////////////////////////

	public void read(Resource res, DataInputStream dis) throws IOException
	{
		readHeader(res, dis);
		m_color = dis.readInt();
		m_tileW = dis.readUnsignedByte();
		m_tileH = dis.readUnsignedByte();
		m_columns = dis.readUnsignedByte();
		m_rows = dis.readUnsignedByte();
		m_layerCount = dis.readByte();
//		Tools.debugPrintln("!!!! m_layerCount="+m_layerCount);
		m_layers = new Layer[m_layerCount];
		for (int i = 0; i < m_layerCount; i++) {
			m_layers[i] = new Layer(this);
			m_layers[i].load(dis);
			m_layers[i].loadImage(res);
			// 如果是物理层
			if (m_layers[i].m_type == Layer.TYPE_PHYSICALLAYER) {
				m_phylayer = m_layers[i];
			}
		}
		checkLoadFinished();
	}

	public void checkLoadFinished()
	{
		for (int i = 0; i < m_layerCount; i++) {
			if (m_layers[i].m_image == null
					&& m_layers[i].m_type != Layer.TYPE_PHYSICALLAYER) {
				m_loadFinished = false;
				return;
			}
		}
		m_loadFinished = true;
	}

	public synchronized void updateComponent(ResHead head,
			Serializeable component)
	{
		if (m_loadFinished)
			return;
		if (head.m_type != ObjectAdapter.RESOURCE_TYPE_PNG)
			return;
		if (m_refsResHead == null || m_refsResHead.length == 0)
			return;
		for (int i = 0; i < m_refsResHead.length; i++) {
			if (m_refsResHead[i].equals(head)) {
				for (int ii = 0; ii < m_layerCount; ii++) {
					if (m_layers[ii].m_imageInx == i) {
						m_layers[ii].m_image = ((SerializeableImage) component).m_image;
					}
				}
				checkLoadFinished();
			}
		}
	}

	public boolean isContainHeader(ResHead head)
	{
		if (head.m_type != ObjectAdapter.RESOURCE_TYPE_PNG)
			return false;
		if (m_refsResHead == null || m_refsResHead.length == 0)
			return false;
		for (int i = 0; i < m_refsResHead.length; i++) {
			if (m_refsResHead[i].equals(head)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 清除资源方法，通常用于游戏状态切换之前调用以腾出内存空间
	 */
	public void dispose()
	{
		disposeHeader();
		// 先清除管理的所有背景层的资源
		for (int i = 0; i < m_layerCount; i++) {
			if (m_layers[i] != null) {
				m_layers[i].dispose();
				m_layers[i] = null;
			}
		}
		m_layers = null;
		m_phylayer = null;
		if (Tools.DEBUG) {
			System.err.println("清除掉卡马克缓存");
		}
	}
}
